package com.centriole.service.workflow.service.parse.component;

import com.centriole.service.workflow.enums.FlowNode;
import com.centriole.service.workflow.util.UserUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多任务节点 封装对象
 *  功   能：
 *  创建人：陈默晗
 *  时   间：2018年1月3日下午2:40:31
 */
public class MultiTaskNode {

    protected String id;              //多任务节点id
    protected String type;
    protected Property property;
    private List<Property.Task> childTasks = new ArrayList<>();

    private static AtomicInteger LINE_COUNTER = new AtomicInteger(0);		//连接线计数器,设置 id 时使用

    protected  String entryNodeId;               //入口连线To节点(第一个并行网关)id
    protected  String exitNodeId;                 //出口连线From节点(排他网关)id
    protected  String joinNodeId;                //第二个并行网关id
    protected  String lineName;		//审批节点的流程变量名
    
    public MultiTaskNode() {}
    public MultiTaskNode(String nodeId){
        this.id = nodeId;
        entryNodeId = id;
        exitNodeId = id+"-exit";
        joinNodeId = id+"-join";
        lineName = "multiTask_line_";
    }

    public MultiTaskNode(String nodeId, String type,List<Property.Task> childTasks) {
        this.id = nodeId;
        this.type = type;
        this.childTasks = childTasks;
        entryNodeId = id;
        exitNodeId = id+"_exit";
        joinNodeId = id+"_join";
        lineName = "multiTask_line_";
    }

    public MultiTaskNode(String nodeId, String type, List<Property.Task> childTasks , Property property) {
        this.id = nodeId;
        this.type = type;
        this.childTasks = childTasks;
        this.property = property;
        entryNodeId = id;
        exitNodeId = id+"_exit";
        joinNodeId = id+"_join";
        lineName = "multiTask_line_";
    }
    
    
    /**
     *  生成对应的bpmn字符串
     * @return String bpmn文件格式的字符串
     */
    public String toBpmnString(){
        //非空检查
        if(StringUtils.isBlank( id ) ) return null;
        
        List<String> exitNodeName = new ArrayList<>();
        
        StringBuilder bpmn = new StringBuilder();
        //拼装内部节点
        bpmn.append( "<inclusiveGateway gatewayDirection=\"Unspecified\" id=\""+entryNodeId+"\" name=\""+"inclusiveGateway"+"\"/>" );
        childTasks.forEach(e->{
        	if( FlowNode.FKUSER.equals(e.getFkType()) ){
        	     bpmn.append("<userTask id=\""+e.getId()+"\" name=\""+e.getName()+"\" activiti:candidateUsers=\""+isCurrentUserAndreplace( e.getFkId() )+"\"></userTask>");
        	}
        	if( FlowNode.FKGROUP.equals(e.getFkType()) ) {
        		   bpmn.append("<userTask id=\""+e.getId()+"\" name=\""+e.getName()+"\" activiti:candidateGroups=\""+e.getFkId()+"\"></userTask>");
        	}
        });
        bpmn.append( "<inclusiveGateway gatewayDirection=\"Unspecified\" id=\""+joinNodeId+"\" name=\""+"inclusiveGateway"+"\"/>" );
        bpmn.append( "<exclusiveGateway gatewayDirection=\"Unspecified\" id=\""+exitNodeId+"\" name=\""+"ExclusiveGateway"+"\"/>" );
     
        //拼接内部连接线
        		//这条线只能出现一次
        bpmn.append("<sequenceFlow id=\""+lineName+(LINE_COUNTER.getAndIncrement())+"\" sourceRef=\""+joinNodeId+"\" targetRef=\""+exitNodeId+"\"/>");
        childTasks.forEach(e->{
            //TODO:这里需要解析有前置条件
            if(StringUtils.isBlank( e.getPreCondition() )){
                bpmn.append("<sequenceFlow id=\""+lineName+(LINE_COUNTER.getAndIncrement())+"\" sourceRef=\""+entryNodeId+"\" targetRef=\""+e.getId()+"\"/>");
            }else{
                bpmn.append(" <sequenceFlow id=\""+lineName+(LINE_COUNTER.getAndIncrement())+"\" sourceRef=\""+entryNodeId+"\" targetRef=\""+e.getId()+"\">" +
                        "<conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${"+e.getPreCondition()+"}]]></conditionExpression>" +
                        "</sequenceFlow>");
            }
            bpmn.append("<sequenceFlow id=\""+lineName+(LINE_COUNTER.getAndIncrement())+"\" sourceRef=\""+e.getId()+"\" targetRef=\""+joinNodeId+"\"/>");
     
            //解析条件
            e.getCondition().entrySet().stream().forEach(condition->{
                //如果出口节点出现过了，则不再连线
            	if(exitNodeName.contains(condition.getKey())) return;  	
                //结束后条件控制到不同的下一节点
                if(condition.getValue().equals("default") ){
                    bpmn.append("<sequenceFlow id=\""+lineName+(LINE_COUNTER.getAndIncrement())+"\" sourceRef=\""+exitNodeId+"\" targetRef=\""+condition.getKey()+"\"/>");
                }
                else{
                    bpmn.append(" <sequenceFlow id=\""+lineName+(LINE_COUNTER.getAndIncrement())+"\" sourceRef=\""+exitNodeId+"\" targetRef=\""+condition.getKey()+"\">" +
                            "<conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${"+condition.getValue()+"}]]></conditionExpression>" +
                            "</sequenceFlow>");
                }
                exitNodeName.add(condition.getKey());
            });
        });
       //替换已经被转义的字符
        return  bpmn.toString().replaceAll("&lt;", "<").replaceAll("&gt;", ">");
    }

    /**
     * 重置连接线计数器
     */
    public static void resetLineCounter() {
    	LINE_COUNTER.set(0);
    }
    
    /**
     * 判断这个fkId 是否是 "${currentUser}" 这个字符串，如果是，则替换成当前session中保存的用户id;
     * @param fkId	String 
     * @return	String
     */
    protected static String isCurrentUserAndreplace(String fkId) {
    	if(FlowNode.CURRENT_USER.equals(fkId)) {
    		return 	UserUtils.currentUserInfo().getEmpId()+"";
    	}
    	return fkId;
    }
    
    
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
        this.entryNodeId = id;
        this.exitNodeId = id+"_exit";
    }

    public List<Property.Task> getChildTasks() {
        return childTasks;
    }

    public void setChildTasks(List<Property.Task> childTasks) {
        this.childTasks = childTasks;
    }

    public String getEntryNodeId() {
        return entryNodeId;
    }

    public String getExitNodeId() {
        return exitNodeId;
    }
	public Property getProperty() {
		return property;
	}
	public void setProperty(Property property) {
		this.property = property;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
    
    
}
